package com.bysj.lms.config;


import com.bysj.lms.Shiro.JwtRealm;
import com.bysj.lms.Shiro.PasswordRealm;
import com.bysj.lms.Shiro.RedisCacheManager;
import com.bysj.lms.Shiro.UserModularRealmAuthenticator;
import com.bysj.lms.filter.JwtFilter;
import com.bysj.lms.utils.EncryptUtil;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.*;
import javax.servlet.Filter;


@Configuration
public class ShiroConfig {

    @Bean
    public RedisCacheManager redisCacheManager(){
        return new RedisCacheManager();
    }

//    @Bean
//    public PasswordRealm shiroRealm(HashedCredentialsMatcher matcher){
//        PasswordRealm passwordRealm = new PasswordRealm();
//        passwordRealm.setCredentialsMatcher(matcher);
//        passwordRealm.setCacheManager(redisCacheManager());
//        passwordRealm.setCachingEnabled(true);//开启全局缓存
//        passwordRealm.setAuthenticationCachingEnabled(true);//开启认证缓存
//        passwordRealm.setAuthenticationCacheName("PW:authenticationCache");
//        passwordRealm.setAuthorizationCachingEnabled(true);//开启授权缓存
//        passwordRealm.setAuthorizationCacheName("PW:authorizationCache");
//        return passwordRealm;
//    }

    /**
     * jwtRealm
     * @return JwtRealm
     */
    @Bean
    public JwtRealm jwtRealm() {
        JwtRealm jwtRealm = new JwtRealm();
//        jwtRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        jwtRealm.setCacheManager(redisCacheManager());
        jwtRealm.setCachingEnabled(true);//开启全局缓存
        jwtRealm.setAuthenticationCachingEnabled(true);//开启认证缓存
        jwtRealm.setAuthenticationCacheName("PW:authenticationCache");
        jwtRealm.setAuthorizationCachingEnabled(true);//开启授权缓存
        jwtRealm.setAuthorizationCacheName("PW:authorizationCache");
        return jwtRealm;
    }

    @Bean("securityManager")
    public DefaultWebSecurityManager getManager(JwtRealm jwtRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        // 使用自己的realm
//        manager.setAuthenticator(userModularRealmAuthenticator);
//        List<Realm> realms = new ArrayList<>();
//        // 添加多个realm
//        realms.add(passwordRealm);
//        realms.add(jwtRealm);
//        manager.setRealms(realms);
        manager.setRealm(jwtRealm);

        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);

        return manager;
    }

//    @Bean
//    public UserModularRealmAuthenticator userModularRealmAuthenticator() {
//        // 自己重写的ModularRealmAuthenticator
//        UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator();
//        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
//        return modularRealmAuthenticator;
//    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JwtFilter());
        factoryBean.setFilters(filterMap);

        factoryBean.setSecurityManager(securityManager);
        factoryBean.setUnauthorizedUrl("/401");

        /*
         * 自定义url规则
         * http://shiro.apache.org/web.html#urls-
         */
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/api/**", "anon");

        filterChainDefinitionMap.put("/druid/**", "anon");//数据库监控
        filterChainDefinitionMap.put("/login", "anon");//放过登录

        //开放swagger
        filterChainDefinitionMap.put("/swagger-ui/index.html", "anon");
        filterChainDefinitionMap.put("/swagger**/**", "anon");
        filterChainDefinitionMap.put("/**/swagger**/**", "anon");
        filterChainDefinitionMap.put("/webjars/**","anon");
        filterChainDefinitionMap.put("/v3/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**", "anon");
        filterChainDefinitionMap.put("/doc.html/**", "anon");

        // 访问401和404页面不通过我们的Filter
        filterChainDefinitionMap.put("/401", "anon");
        // filterChainDefinitionMap.put("/toLogin", "anon");

        //最后的整体拦截
        filterChainDefinitionMap.put("/**", "jwt");


        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return factoryBean;
    }
    /**
     * 密码登录时指定匹配器，
     *
     * @return HashedCredentialsMatcher
     */
    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        // 设置哈希算法名称
        matcher.setHashAlgorithmName(EncryptUtil.algorithmName);
        // 设置哈希迭代次数
        matcher.setHashIterations(EncryptUtil.hashIterations);
        // 设置存储凭证十六进制编码
        matcher.setStoredCredentialsHexEncoded(EncryptUtil.hexEncode);
        return matcher;
    }
    /**
     *
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),<br>
     * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     *
     * @return DefaultAdvisorAutoProxyCreator
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }


    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }



    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}
